package com.zzt.glideapp;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.widget.ImageView;

import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.signature.ObjectKey;
import com.zzt.zt_glideapputil.R;

import java.io.File;


/**
 * Glide工具类
 *
 * @author: zeting
 * @date: 2022/10/20
 */
public class GlideAppUtils {
    private static final String TAG = GlideAppUtils.class.getSimpleName();
    /*** 占位图 */
    public static int placeholderImage = 0;
    /*** 错误图 */
    public static int errorImage = 0;
    // 图片缓存签名
    private long glideSignature = 0;

    private static volatile GlideAppUtils instance;

    public GlideAppUtils() {
        glideSignature = System.currentTimeMillis();
    }

    public static GlideAppUtils getInstance() {
        if (instance == null) {
            synchronized (GlideAppUtils.class) {
                if (instance == null) {
                    instance = new GlideAppUtils();
                }
            }
        }
        return instance;
    }

    public static int getPlaceholderImage() {
        return placeholderImage;
    }

    public static void setPlaceholderImage(int placeholderImage) {
        GlideAppUtils.placeholderImage = placeholderImage;
    }

    public static int getErrorImage() {
        return errorImage;
    }

    public static void setErrorImage(int errorImage) {
        GlideAppUtils.errorImage = errorImage;
    }

    /**
     * 初始化签名信息，用于每次加载都能是最新的
     */
    public void initGlideSignature() {
        glideSignature = System.currentTimeMillis();
    }

    /**
     * 获取签名信息
     *
     * @return
     */
    public long getGlideSignature() {
        return glideSignature;
    }

    /**
     * 监听，处理失败删除缓存或者是重新加载
     *
     * @param <Drawable>
     */
    static class MRequestListener<Drawable> implements RequestListener<Drawable> {
        private Context context;
        private String url;
        private ImageView imageView;
        private RequestOptions options;
        private long laseSignature = 0; // 上一次签名

        public MRequestListener(Context context, String url, ImageView imageView, RequestOptions options) {
            this.context = context;
            this.url = url;
            this.imageView = imageView;
            this.options = options;
        }

        public MRequestListener(Context context, String url, ImageView imageView, RequestOptions options, long laseSignature) {
            this.context = context;
            this.url = url;
            this.imageView = imageView;
            this.options = options;
            this.laseSignature = laseSignature;
        }

        @Override
        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
            // 当前请求失败，记录失败日志，上传失败信息
            return false;
        }

        @Override
        public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
            return false;
        }
    }

    /**
     * 加载图片
     *
     * @param context
     * @param url
     * @param imageView
     * @param options         加载选项配置
     * @param requestListener 加载监听
     */
    public void loadGlideOption(Context context, String url, ImageView imageView,
                                RequestOptions options, @Nullable RequestListener<Drawable> requestListener) {
        Glide.with(context)
                .load(url)
                .apply(options)
                .addListener(requestListener)
                .error(Glide.with(context)
                        .load(url)
                        .apply(options)
                        .signature(new ObjectKey(getGlideSignature() + 1))) // 失败了，就不在读取缓存重新加载一次
                .into(imageView);
    }


    /**
     * 加载图片(默认)
     *
     * @param context   上下文
     * @param url       链接
     * @param imageView ImageView
     */
    public void loadImage(Context context, String url, ImageView imageView) {
        RequestOptions options = new RequestOptions()
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图
        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }


    /**
     * 默认加载
     *
     * @param context
     * @param url
     * @param imageView
     */
    public void loadImageSignature(Context context, String url, ImageView imageView) {
        loadImageSignature(context, url, imageView, glideSignature);
    }

    /**
     * 默认加载，给个签名信息，重新从网络上加载
     *
     * @param context
     * @param url
     * @param imageView
     * @param sign      签名信息
     */
    public void loadImageSignature(Context context, String url, ImageView imageView, long sign) {
        RequestOptions options = new RequestOptions()
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图
        Glide.with(context)
                .load(url)
                .apply(options)
                .signature(new ObjectKey(sign))  // 设置图片签名
                .addListener(new MRequestListener<>(context, url, imageView, options, sign))
                .error(Glide.with(context)
                        .load(url)
                        .apply(options)
                        .signature(new ObjectKey(getGlideSignature() + 1)))
                .into(imageView);
    }


    /**
     * 指定图片大小;使用override()方法指定了一个图片的尺寸。
     * Glide现在只会将图片加载成width*height像素的尺寸，而不会管你的ImageView的大小是多少了。
     * 如果你想加载一张图片的原始尺寸的话，可以使用Target.SIZE_ORIGINAL关键字----override(Target.SIZE_ORIGINAL)
     *
     * @param context
     * @param url
     * @param imageView
     * @param width     图片宽度
     * @param height    图片高度
     */
    public void loadImageSize(Context context, String url, ImageView imageView, int width, int height) {
        RequestOptions options = new RequestOptions()
                .placeholder(placeholderImage) //占位图
                .error(errorImage)             //错误图
                .override(width, height)
                .priority(Priority.HIGH);

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }


    /**
     * 加载正方形图片
     *
     * @param context
     * @param url
     * @param imageView
     */
    public void loadSquareImage(Context context, String url, ImageView imageView) {
        RequestOptions options = RequestOptions.bitmapTransform(
                new MultiTransformation<>(
                        new CenterCrop(),
                        new CropSquareTransformation()
                ))
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }


    /**
     * 加载圆形图片
     *
     * @param context
     * @param url
     * @param imageView
     */
    public void loadCircleImage(Context context, String url, ImageView imageView) {
        RequestOptions options = new RequestOptions()
                .centerCrop()
                .circleCrop()//设置圆形
                .placeholder(placeholderImage) //占位图
                .error(errorImage)             //错误图
                .priority(Priority.HIGH);

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }

    /**
     * 加载圆形带边框图片
     *
     * @param context
     * @param url
     * @param imageView
     * @param borderSize  边框宽度 px
     * @param borderColor 边框颜色
     */
    public void loadCircleWithBorderImage(Context context, String url, ImageView imageView,
                                          float borderSize, @ColorInt int borderColor) {
        RequestOptions options = RequestOptions.bitmapTransform(
                new MultiTransformation<>(
                        new CenterCrop(),
                        new CropCircleWithBorderTransformation(GlideSizeUtils.dp2px(context, borderSize), borderColor)
                ))
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图
        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }

    /**
     * 加载圆角图片
     *
     * @param context
     * @param url
     * @param imageView
     * @param radius    圆角 px
     */
    public void loadRoundCircleImage(Context context, String url, ImageView imageView, float radius) {
        RequestOptions options = RequestOptions.bitmapTransform(
                new MultiTransformation<>(
                        new CenterCrop(),
                        new RoundedCornersTransformation(GlideSizeUtils.dp2px(context, radius), 0,
                                RoundedCornersTransformation.CornerType.ALL)
                ))
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }

    /**
     * 加载圆角图片
     *
     * @param context
     * @param url
     * @param imageView
     * @param radius    圆角 px
     */
    public void loadRoundCircleImageV1(Context context, String url, ImageView imageView, float radius) {
        RequestOptions options = RequestOptions.bitmapTransform(
                new MultiTransformation<>(
                        new CenterCrop(), // 以填满整个ImageView为目的，将原图的中心对准ImageView的中心，等比例放大原图，直到填满ImageView为止（指的是ImageView的宽和高都要填满），原图超过ImageView的部分作裁剪处理。
//                        new FitCenter(),// 把图片按比例扩大/缩小到View的宽度，居中显示
//                        new CenterInside(),// 以原图完全显示为目的，将图片的内容完整居中显示，通过按比例缩小原图的size宽(高)等于或小于ImageView的宽(高)。如果原图的size本身就小于ImageView的size，则原图的size不作任何处理，居中显示在ImageView。
//                        new CircleCrop(), // 圆
//                        new Rotate(90),
                        new RoundedCorners(GlideSizeUtils.dp2px(context, radius))
                ))
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }


    /**
     * 加载圆角图片-指定任意部分圆角（图片上、下、左、右四个角度任意定义）
     *
     * @param context
     * @param url
     * @param imageView
     * @param radius    圆角 px
     * @param type      圆角位置
     */
    public void loadRoundCircleImage(Context context, String url, ImageView imageView,
                                     float radius, RoundedCornersTransformation.CornerType type) {
        RequestOptions options = RequestOptions.bitmapTransform(
                new MultiTransformation<>(
                        new CenterCrop(),
                        new RoundedCornersTransformation(GlideSizeUtils.dp2px(context, radius), 0, type)
                ))
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }

    /**
     * Glide.with(this)
     * .asGif()    //强制指定加载动态图片
     * 如果加载的图片不是gif，则asGif()会报错， 当然，asGif()不写也是可以正常加载的。
     * 加入了一个asBitmap()方法，这个方法的意思就是说这里只允许加载静态图片，不需要Glide去帮我们自动进行图片格式的判断了。
     * 如果你传入的还是一张GIF图的话，Glide会展示这张GIF图的第一帧，而不会去播放它。
     *
     * @param context
     * @param url
     * @param imageView
     */
    private void loadGif(Context context, String url, ImageView imageView) {
        RequestOptions options = new RequestOptions()
                .placeholder(placeholderImage) //占位图
                .error(errorImage);            //错误图

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));
    }

    /**
     * 禁用内存缓存功能
     * diskCacheStrategy()方法基本上就是Glide硬盘缓存功能的一切，它可以接收五种参数：
     * DiskCacheStrategy.NONE： 表示不缓存任何内容。
     * DiskCacheStrategy.DATA： 表示只缓存原始图片。
     * DiskCacheStrategy.RESOURCE： 表示只缓存转换过后的图片。
     * DiskCacheStrategy.ALL ： 表示既缓存原始图片，也缓存转换过后的图片。
     * DiskCacheStrategy.AUTOMATIC： 表示让Glide根据图片资源智能地选择使用哪一种缓存策略（默认选项）。
     *
     * @param context
     * @param url
     * @param imageView
     */
    public void loadImageSizeKipMemoryCache(Context context, String url, ImageView imageView) {
        RequestOptions options = new RequestOptions()
                .placeholder(placeholderImage) //占位图
                .error(errorImage)             //错误图
                .skipMemoryCache(true)          //跳过内存缓存
                .diskCacheStrategy(DiskCacheStrategy.NONE); // 跳过磁盘缓存

        loadGlideOption(context, url, imageView, options, new MRequestListener<>(context, url, imageView, options));

    }

    /**
     * 预先加载图片
     * 在使用图片之前，预先把图片加载到缓存，调用了预加载之后，我们以后想再去加载这张图片就会非常快了，
     * 因为Glide会直接从缓存当中去读取图片并显示出来
     *
     * @param context
     * @param url
     */
    public void preloadImage(Context context, String url) {
        Glide.with(context)
                .load(url)
                .preload();
    }

    /**
     * 下载图片
     *
     * @param context
     * @param url
     * @param requestListener 下载监听
     */
    public void downloadImage(final Context context, final String url, RequestListener<File> requestListener) {
        Glide.with(context)
                .downloadOnly()
                .load(url)
                .addListener(requestListener)
                .preload();
    }

}